import random
import time
import heapq
import matplotlib.pyplot as plt
import networkx as nx


class TrafficSimulator:  # 初始化道路、车辆位置、交通流量
    def __init__(self, num_roads=5, num_vehicles=20, simulation_time=60):
        self.num_roads = num_roads
        self.num_vehicles = num_vehicles
        self.simulation_time = simulation_time
        self.roads = [f"Road_{i}" for i in range(num_roads)]
        self.vehicle_locations = {f"Vehicle_{i}": random.choice(self.roads) for i in range(num_vehicles)}
        self.traffic_flow = {road: 0 for road in self.roads}
        self.time = 0

    def simulate_step(self):  # 模拟车辆移动，更新交通流量
        self.time += 1
        for vehicle, location in self.vehicle_locations.items():
            if random.random() < 0.3:  # 30% 如果车辆数量通过了百分之30
                new_location = random.choice(self.roads)
                self.vehicle_locations[vehicle] = new_location
        self.update_traffic_flow()

    def update_traffic_flow(self):  # 更新车辆移动信息
        self.traffic_flow = {road: 0 for road in self.roads}
        for location in self.vehicle_locations.values():
            self.traffic_flow[location] += 1

    def get_traffic_data(self):  # 返回当前时间和交通流量数据
        return self.time, self.traffic_flow


class TrafficAnalyzer:  # 初始化拥堵阈值
    def __init__(self, congestion_threshold=5):
        self.congestion_threshold = congestion_threshold
        self.congestion_events = []

    def analyze_traffic(self, time, traffic_flow):  # 检测拥堵事件
        for road, flow in traffic_flow.items():
            if flow > self.congestion_threshold:
                self.congestion_events.append((time, road, flow))

    def get_congestion_events(self):  # 返回拥堵事件列表
        return self.congestion_events


class SignalController:  # 初始化信号灯时长、当前信号
    def __init__(self, roads, base_signal_time=10):
        self.roads = roads
        self.base_signal_time = base_signal_time
        self.signal_times = {road: base_signal_time for road in roads}
        self.current_signal = random.choice(roads)
        self.time_left = self.signal_times[self.current_signal]

    def update_signal(self, traffic_flow):  # 根据交通流量动态调整信号灯
        self.time_left -= 1
        if self.time_left <= 0:
            max_flow_road = max(traffic_flow, key=traffic_flow.get)
            self.current_signal = max_flow_road
            self.signal_times[self.current_signal] = self.base_signal_time + traffic_flow[self.current_signal]
            self.time_left = self.signal_times[self.current_signal]

    def get_current_signal(self):  # 返回当前信号灯
        return self.current_signal


class PathPlanner:  # 初始化道路网络图
    def __init__(self, graph):
        self.graph = graph

    def dijkstra(self, start, end):  # 实现 Dijkstra 算法
        distances = {node: float('inf') for node in self.graph}
        distances[start] = 0
        priority_queue = [(0, start)]
        previous_nodes = {node: None for node in self.graph}

        while priority_queue:
            current_distance, current_node = heapq.heappop(priority_queue)

            if current_distance > distances[current_node]:
                continue

            for neighbor, weight in self.graph[current_node].items():
                distance = current_distance + weight
                if distance < distances[neighbor]:
                    distances[neighbor] = distance
                    previous_nodes[neighbor] = current_node
                    heapq.heappush(priority_queue, (distance, neighbor))

        path = []
        current = end
        while current is not None:
            path.insert(0, current)
            current = previous_nodes[current]

        return path if distances[end] != float('inf') else None

    def plan_path(self, start, end, traffic_flow):  # 根据交通流量动态规划路径
        # 动态调整权重
        dynamic_graph = {node: {} for node in self.graph}
        for node, neighbors in self.graph.items():
            for neighbor, weight in neighbors.items():
                dynamic_weight = weight + traffic_flow.get(neighbor, 0)
                dynamic_graph[node][neighbor] = dynamic_weight
        return self.dijkstra(start, end)


def create_road_network():  # 创建一个简单的道路网络图
    graph = {
        "Road_0": {"Road_1": 1, "Road_2": 2},
        "Road_1": {"Road_0": 1, "Road_3": 3},
        "Road_2": {"Road_0": 2, "Road_4": 4},
        "Road_3": {"Road_1": 3, "Road_4": 1},
        "Road_4": {"Road_2": 4, "Road_3": 1}
    }
    return graph


def visualize_network(graph):  # 使用 networkx 可视化道路网络
    G = nx.DiGraph(graph)
    pos = nx.spring_layout(G)
    nx.draw(G, pos, with_labels=True, node_color='skyblue', node_size=1500, edge_color='gray', arrowsize=20)
    nx.draw_networkx_edge_labels(G, pos, edge_labels=nx.get_edge_attributes(G, 'weight'))
    plt.title("Road Network")
    plt.show()


def main():
    # 创建模拟器、分析器、控制器、路径规划器
    # 模拟交通，分析数据，控制信号灯
    # 打印拥堵事件，规划路径
    # 可视化交通流量数据
    num_roads = 5
    num_vehicles = 20
    simulation_time = 60
    congestion_threshold = 5
    base_signal_time = 10

    road_network = create_road_network()
    visualize_network(road_network)

    simulator = TrafficSimulator(num_roads, num_vehicles, simulation_time)
    analyzer = TrafficAnalyzer(congestion_threshold)
    controller = SignalController(simulator.roads, base_signal_time)
    planner = PathPlanner(road_network)

    time_data = []
    flow_data = []
    congestion_data = []

    for _ in range(simulation_time):
        simulator.simulate_step()
        time, traffic_flow = simulator.get_traffic_data()
        analyzer.analyze_traffic(time, traffic_flow)
        controller.update_signal(traffic_flow)

        time_data.append(time)
        flow_data.append(traffic_flow)
        congestion_data.append(analyzer.get_congestion_events())

        print(f"Time: {time}, Traffic Flow: {traffic_flow}, Current Signal: {controller.get_current_signal()}")

    print("\nCongestion Events:")
    for event in analyzer.get_congestion_events():
        print(f"Time: {event[0]}, Road: {event[1]}, Flow: {event[2]}")

    # 路径规划示例
    start_road = "Road_0"
    end_road = "Road_4"
    path = planner.plan_path(start_road, end_road, simulator.traffic_flow)
    if path:
        print(f"\nPath from {start_road} to {end_road}: {path}")
    else:
        print(f"\nNo path found from {start_road} to {end_road}")

    # 可视化流量数据
    plt.figure(figsize=(12, 6))
    for road in simulator.roads:
        road_flow = [flow[road] for flow in flow_data]
        plt.plot(time_data, road_flow, label=road)
    plt.xlabel("Time")
    plt.ylabel("Traffic Flow")
    plt.title("Traffic Flow Over Time")
    plt.legend()
    plt.grid(True)
    plt.show()


if __name__ == "__main__":
    main()

# 输出结果：
# 控制台会输出每个时间步的交通流量、当前信号灯、拥堵事件
# 会显示道路网络图
# 会显示从指定起点到终点的路径
# 会显示交通流量随时间变化的图表
